/**
 *  @author 侯庆峰, 15/11/18.
 *
 *  @brief LTHttpClient.mm is used for LetvCurlRequest.h .
 *
 *  @copyright © 2015年 letv. All rights reserved.
 */

#import <CFNetwork/CFProxySupport.h>

#import "LTHttpClient.h"
#import "LTOperationManager.h"

#define GetErrorDomain @"Get Error!"
#define PostErrorDomain @"Post Error!"

/**
 *  全局存储所有request请求
 */
static NSMutableArray *requestArray = [[NSMutableArray alloc] init];
static mutex mtx;

@interface LTHttpClient()

- (id) init;

@property (nonatomic,assign)long startTime;
@property (nonatomic,strong)NSString *url;//url地址
@property (nonatomic,strong)NSData *postData;//post数据

@property (nonatomic,strong)LTCurlCompleteBlock completionBlock;//请求成功回调函数
@property (nonatomic,strong)LTCurlErrorBlock errorBlock;//请求失败回调函数

@property (nonatomic,assign)BOOL cancelRequestMark;//取消请求标志
@property (nonatomic,assign)int timeout;//超时时间

@property (nonatomic,strong)NSString *proxy;//代理地址
@property (nonatomic, strong)NSDictionary *proxySettings;//机器代理信息

@property (nonatomic,assign)map<string, string> httpHeaderMap;//http报文头
@property (nonatomic,assign)LTHttpOperation *operation;//请求操作

/**
 *  设置通用参数
 */
- (bool)setParameter:(NSString *)url
                data:(NSData *)data
             timeout:(int)timeout
          httpHeader:(NSDictionary*)httpHeaderDic
   completionHandler:(LTCurlCompleteBlock)completionBlock
        errorHandler:(LTCurlErrorBlock)errorBlock;

/**
 *  NSDictionary 转化成 map 类型
 */
- (void)setHttpHeader:(NSDictionary*)httpHeaderDic;

/**
 *  获得代理服务器
 */
- (NSString *)getProxy;

- (void)dealloc;

@end

@implementation LTHttpClient

- (id) init
{
    if (self = [super init]){
        _cancelRequestMark = NO;
    }
    
    return self;
}

-(bool) setParameter:(NSString *)url
                data:(NSData *)data
             timeout:(int)timeout
          httpHeader:(NSDictionary*)httpHeaderDic
   completionHandler:(LTCurlCompleteBlock)completionBlock
        errorHandler:(LTCurlErrorBlock)errorBlock
{
    bool exception = true;//是否可以进行异常处理
    if (errorBlock == nil) {
        exception = false;
    }
    
    self.url = url;
    if (!timeout) {
        self.timeout = 0;
    } else {
        if (timeout < 0) {
            self.timeout = 0;
        } else {
            self.timeout = timeout;
        }
    }
    
    self.postData = data;
    [self setHttpHeader:httpHeaderDic];
    self.completionBlock = completionBlock;
    self.errorBlock = errorBlock;
    
    /**
     *  异常处理
     */
    if (exception) {
        if (url == nil) {
            NSError *nserror = [[NSError alloc] initWithDomain:@"URL is null, please checkout url!"
                                                          code:-1 userInfo:nil];
            self.errorBlock(nserror);
            return false;
        }
    }
    
    return true;
}


-(NSString *)getProxy{
    
    NSDictionary *proxySettings =(__bridge NSDictionary *)CFNetworkCopySystemProxySettings();
    
    if (proxySettings == nil) {
        return nil;
    }
    
    NSString *ipaddr = [[NSString alloc] init];
    NSNumber *port;
    
    if ([_url hasPrefix:@"https"]) {
        ipaddr = [proxySettings objectForKey:@"HTTPSProxy"];
        port = [proxySettings objectForKey:@"HTTPSPort"];
    } else {
        ipaddr = [proxySettings objectForKey:@"HTTPProxy"];
        port = [proxySettings objectForKey:@"HTTPPort"];
    }
    
    if (ipaddr && port) {
        ipaddr = [ipaddr stringByAppendingString:@":"];
        NSString *str = [NSString stringWithFormat:@"%@",port];
        ipaddr = [ipaddr stringByAppendingString:str];
    } else {
        ipaddr = nil;
    }
    
    return ipaddr;
}

void CurlCallc(void* buffer, size_t length, bool Sucess, void *context)
{
    if (!context){
        return;
    }
    
    LTHttpClient *curlRequest = (__bridge LTHttpClient*)context;
    
    if (curlRequest.cancelRequestMark){
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if(Sucess){
            char *ch = (char*)buffer;
            NSData *nsdata = [[NSData alloc] initWithBytes:ch length:length];
            if (curlRequest.completionBlock != nil) {
                //@lyh TODO:网络接口上报参数传递
                long endTime = [[NSDate date] timeIntervalSince1970]*1000;
                NSDictionary * extraDic =@{
                                           @"startTime":[NSNumber numberWithLong:curlRequest.startTime],
                                           @"endTime":[NSNumber numberWithLong:endTime]};
                if (curlRequest.cancelRequestMark == NO) {
                    curlRequest.completionBlock(nsdata,extraDic);
                }
            }
        } else{
            NSError *nserror = [[NSError alloc] initWithDomain:[NSString stringWithUTF8String:(char*)buffer] code:-1 userInfo:nil];
            
            if (curlRequest.errorBlock != nil && curlRequest.cancelRequestMark == NO) {
                curlRequest.errorBlock(nserror);
            }
        }
    });
    
    mtx.lock();
    if(requestArray) {
        if (curlRequest) {
            [requestArray removeObject:curlRequest];
        }
    }
    mtx.unlock();
}

/**
 *  GetRequest
 *
 *  @param url             url
 *  @param timeout         timeout
 *  @param httpHeaderDic   http
 *  @param completionBlock completed callc
 *  @param errorBlock      error callc
 */
- (void)GET:(NSString*)url
    timeout:(int)timeout
 httpHeader:(NSDictionary*)httpHeaderDic
completionHandler:(LTCurlCompleteBlock)completionBlock
errorHandler:(LTCurlErrorBlock) errorBlock
{
    bool parameterException = [self setParameter:url
                                            data:Nil
                                         timeout:timeout
                                      httpHeader:httpHeaderDic
                               completionHandler:completionBlock
                                    errorHandler:errorBlock];
    if (!parameterException) { //参数设置失败
        return;
    }
    _proxy = [self getProxy];
    
    mtx.lock();
    if(requestArray) {
        if(self != nil){
            [requestArray addObject:self];
        }
    }
    mtx.unlock();
    const char *curlUrl = [url UTF8String];
    long urlLength = [url length];
    
    if (self.operation == nil) {
        self.operation = LTOperationManager::GetInstance()->CreateOperation();
    }
    
    long proxyLength = [self.proxy length];
    const char *curlProxy = [self.proxy UTF8String];
    
    _operation->GetRequest(curlUrl, urlLength,(long)timeout, _httpHeaderMap,
                           (__bridge void*)self, (char*)curlProxy, proxyLength, CurlCallc);
    
    self.startTime = [[NSDate date] timeIntervalSince1970]*1000;
    
    LTOperationManager::GetInstance()->AddOperation(_operation);
}

- (void) POST:(NSString*)url
         data:(NSData*)data
      timeout:(int)timeout
   httpHeader:(NSDictionary*)httpHeaderDic
completionHandler:(LTCurlCompleteBlock)completionBlock
 errorHandler:(LTCurlErrorBlock) errorBlock
{
    bool parameterException = [self setParameter:url
                                            data:data
                                         timeout:timeout
                                      httpHeader:httpHeaderDic
                               completionHandler:completionBlock
                                    errorHandler:errorBlock];
    
    if (!parameterException) { //参数设置失败
        return;
    }
    
    const char *curlUrl = [url UTF8String];
    long urlLength = [url length];
    long dataLength = [self.postData length];
    void *tempData = (char*)[self.postData bytes];
    
    _proxy = [self getProxy];
    mtx.lock();
    if(requestArray) {
        if(self != nil){
            [requestArray addObject:self];
        }
    }
    mtx.unlock();
    
    if (self.operation == nil) {
        self.operation = LTOperationManager::GetInstance()->CreateOperation();
    }
    
    const char *curlProxy = [self.proxy UTF8String];
    long proxyLength = [self.proxy length];
    _operation->PostRequest(curlUrl, urlLength, (long)timeout, _httpHeaderMap,
                            (__bridge void*)self, tempData, dataLength,
                            (char*)curlProxy, proxyLength, CurlCallc);
    
    LTOperationManager::GetInstance()->AddOperation(_operation);
}

/**
 *  设置http报文头
 *
 *  @param httpHeaderDic http报文头字典
 */
- (void)setHttpHeader:(NSDictionary*)httpHeaderDic
{
    if (httpHeaderDic == nil) {
        return;
    }
    
    for(id key in httpHeaderDic){
        NSString *value = [httpHeaderDic objectForKey:key];
        string strKey = [key UTF8String];
        string strValue = [value UTF8String];
        _httpHeaderMap.insert(make_pair(strKey, strValue));
    }
}

/**
 *  取消Request请求(request对象取消)
 */
- (void)cancelRequest
{
    @synchronized(self) {
        self.cancelRequestMark = YES;//关闭回调函数;
    }
    mtx.lock();
    if(requestArray) {
        [requestArray removeObject:self];
    }
    mtx.unlock();
}

/**
 *  取消Request请求(使用url取消)
 */
+ (void)cancelRequest:(NSString*)url
{
    mtx.lock();
    NSArray * array = [NSArray arrayWithArray: requestArray];
    for(LTHttpClient* request in array) {
        if ([request.url isEqualToString:url]) {
            if(requestArray) {
                @synchronized(request) {
                    request.cancelRequestMark = YES;//关闭回调函数;
                }
                [requestArray removeObject:request];
            }
        }
    }
    mtx.unlock();
}

+ (void)cancelRequestWithTag:(NSInteger)tag
{
    mtx.lock();
    NSArray * array = [NSArray arrayWithArray: requestArray];
    for(LTHttpClient* request in array) {
        if (request.tag == tag) {
            if(requestArray) {
                @synchronized(request) {
                    request.cancelRequestMark = YES;//关闭回调函数;
                }
                [requestArray removeObject:request];
            }
        }
    }
    mtx.unlock();
}

- (void)dealloc
{
    if(_operation)
    {
        LTOperationManager::GetInstance()->DeleteOperation(_operation);
        _operation = NULL;
    }
}
@end